Data Types
Primitive Data Types
Primitive types are the basic, immutable data types.
- Immutable → The value itself cannot be changed (though variables can be reassigned).
- Stored in stack memory (for fast access).
- Compared by value (two primitives are equal if their values are equal).
List of Primitive Types
- String → Text data
- Number → Integers, floats,
NaN,Infinity - BigInt → Large integers beyond
Numberlimit - Boolean →
trueorfalse - Undefined → Declared but not assigned
- Null → Intentional absence of value
- Symbol → Unique identifiers
Example of Primitive Types
// String
let name = "Masum";
console.log(typeof name); // string
// Number
let age = 25;
let pi = 3.14;
console.log(typeof pi); // number
// BigInt
let bigNumber = 1234567890123456789012345678901234567890n;
console.log(typeof bigNumber); // bigint
// Boolean
let isActive = true;
console.log(typeof isActive); // boolean
// Undefined
let x;
console.log(typeof x); // undefined
// Null
let y = null;
console.log(typeof y); // object (quirk in JS)
// Symbol
let sym1 = Symbol("id");
let sym2 = Symbol("id");
console.log(sym1 === sym2); // false (always unique)
null is of type "object" → This is a historical bug in JavaScript.
Non-Primitive (Reference) Data Types
Non-primitive types are objects (including arrays, functions, dates, etc).
- Mutable → Values can be changed.
- Stored in heap memory, and variables hold a reference (address), not the actual value.
- Compared by reference, not by value (two objects are equal only if they reference the same memory).
List of Non-Primitive Types
- Object → Key-value pairs
- Array → Ordered list of values
- Function → Callable objects
- Date, RegExp, Map, Set, WeakMap, WeakSet, etc.
Example of Non-Primitive Types
// Object
let person = { name: "Masum", age: 25 };
console.log(typeof person); // object
// Array
let numbers = [1, 2, 3];
console.log(typeof numbers); // object (arrays are special objects)
// Function
function greet() {
console.log("Hello!");
}
console.log(typeof greet); // function
// Date
let today = new Date();
console.log(typeof today); // object
Key Difference: Value vs Reference
// Primitive (value copy)
let a = 10;
let b = a; // copy value
b = 20;
console.log(a); // 10 (unchanged)
console.log(b); // 20
// Non-Primitive (reference copy)
let obj1 = { value: 10 };
let obj2 = obj1; // copy reference
obj2.value = 20;
console.log(obj1.value); // 20 (changed!)
console.log(obj2.value); // 20
- Primitive → copies the value
- Non-Primitive → copies the reference (address)
Value vs Reference Comparison Table
| Feature | Primitive | Non-Primitive (Reference) |
|---|---|---|
| Examples | String, Number, Boolean, Null, Undefined, BigInt, Symbol | Object, Array, Function, Date, Map, Set, etc. |
| Mutable? | Immutable | Mutable |
| Stored in | Stack memory | Heap memory |
| Assigned by | Value | Reference (address) |
| Comparison | By value (===) | By reference (===) |
| Size | Fixed | Dynamic |
Wrapper Objects
Even though primitives are not objects, JavaScript automatically wraps them in an object when you try to access properties or methods.
- This wrapper object is temporary, only exists during property/method access.
- The primitive itself remains unchanged.
let str = "hello";
console.log(str.toUpperCase()); // "HELLO"
// JS internally does:
// new String("hello").toUpperCase();
let bool = true;
console.log(bool.valueOf()); // true
// JS internally does:
// new Boolean(true).valueOf();
Why Wrapper Objects Are Considered Non-Primitive
- Primitives themselves do not have methods or properties.
- Wrapper objects like
String,Number,Booleanare actual objects. - When you call a method on a primitive, JavaScript creates a temporary wrapper object, which is non-primitive, executes the method, and then discards the object.
let str = "hello";
console.log(typeof str); // "string" (primitive)
console.log(typeof new String(str)); // "object" (wrapper)
So, wrapper objects are non-primitive, even though they represent primitive values.
Using wrapper objects explicitly (e.g., new String("hello")) is generally discouraged, because it creates object instances which behave differently:
const s1 = "hello";
const s2 = new String("hello");
console.log(s1 == s2); // true (value comparison)
console.log(s1 === s2); // false (different types)
Built-in Wrapper Objects
| Primitive Type | Wrapper Object | Example |
|---|---|---|
| string | String | "hello".toUpperCase() |
| number | Number | (42).toString() |
| boolean | Boolean | true.valueOf() |
| symbol | Symbol | Object(Symbol("id")).toString() |
Note: null and undefined do not have wrappers, trying to access properties on them throws an error.